Skip to content

feat:prover-db-indexer- add OCW consumer that drains and forwards events#192

Merged
rishitesh-snt merged 2 commits into
mainfrom
feat/prover-db-4-consumer
May 28, 2026
Merged

feat:prover-db-indexer- add OCW consumer that drains and forwards events#192
rishitesh-snt merged 2 commits into
mainfrom
feat/prover-db-4-consumer

Conversation

@rishitesh-snt

Copy link
Copy Markdown
Contributor

Summary

Final PR in the prover-db-indexer stack: wires up the offchain worker that consumes what PR 2 (#187) writes to the offchain DB and POSTs it through the HTTP+protobuf client from PR 3 (#190).

Behavior

  • Lock-serialized rounds. Substrate spawns offchain_worker for every imported block; without serialization, two concurrent rounds would read the same server checkpoint and double-submit
    create_table/drop_table/put_batches. StorageLock<Time> with a configurable deadline (Config::OcwLockDeadlineMs, default 120 s) makes overlapping invocations no-ops.
  • Dormant by default. Reads the indexer URL from offchain local storage (PROVER_DB_URL_KEY); skips silently if unset, so non-indexer nodes pay nothing.
  • Server is the source of truth. Each round asks the server for its last checkpoint sequence number — no local cursor, no divergence. A failure here is treated as transient (log + skip the round); the next
    OCW retries.
  • Bounded catch-up. Walks cursor+1..=tip capped at Config::MaxBlocksPerInvocation (default 100 — ~100× realtime at 6 s block time). Lower values bound per-round cost; higher values close a wider gap
    faster after downtime.
  • Per-block forwarding. Reads the per-block high-water-mark, probes key_for_event(block, 0..=hwm) in extrinsic order, POSTs each present payload via the HTTP client, deletes the consumed offchain entries,
    then checkpoints the block on the server (even if it had zero captures, so the server's view doesn't lag empty blocks).

Notable implementation details

  • ConsumerError Snafu enum keeps the consumer stack typed end-to-end: each http_client::Error is wrapped with the failing operation (CreateTable/DropTable/PutBatches/Checkpoint) so the operator
    log line names both. The OCW hook formats it with its Display impl and emits via polkadot_sdk::sp_tracing::error!.
  • MaxBlocksPerInvocation and OcwLockDeadlineMs are #[pallet::constant] type Get<u64> items so other chains can override them and so they show up in the pallet's metadata (visible in polkadot.js UI).
    Wired with ConstU64<100> / ConstU64<120_000> in runtime/src/lib.rs.
  • commitment_sql::ROW_NUMBER_COLUMN_NAME is reused rather than redeclared — the indexer's dedup-key column is the same META_ROW_NUMBER value the schema rewriter injects. Pub'd in commitment-sql so the
    pallet doesn't duplicate the constant.
  • Tests use TestOffchainExt + a recording HTTP transport in the mock to exercise the full forward path: golden path, multi-block cursors, partial blocks (high-water-mark with gaps in extrinsic indices),
    empty blocks, lock contention, and resumption from a server checkpoint mid-stream. 9 tests, all green.
  • Dev-deps are minimal. Only parking_lot (for the RwLock upstream's TestOffchainExt::new hands back). The mock + tests don't reference any other pallet.

Test plan

  • cargo test -p pallet-prover-db-indexer — 9 OCW tests
  • cargo check --workspace clean
  • cargo f clean (workspace formatter)
  • Manual smoke test: run the node with --prover-db-url http://127.0.0.1:<port> against the prb-service indexer at sxtdb/prb-service; create a table via pallet-tables::create_tables, submit data, watch
    the OCW round forward create_table + put_batches to the indexer's v1 HTTP API.

Stacked PRs

This is PR 3 of 3 in the prover-db-indexer stack:

…ents

Builds on the HTTP+protobuf client from the previous PR; wires it into a
Substrate offchain worker that:

- Acquires an OCW storage lock (deadline configurable via
  `Config::OcwLockDeadlineMs`) so overlapping rounds don't double-submit.
- Reads the indexer URL from offchain local storage (key in `sxt-core`)
  and skips silently if unset, so non-indexer nodes pay nothing.
- Asks the server for its last checkpoint sequence number — the server
  is the sole source of truth, no local cursor.
- Walks blocks `cursor+1..=tip` capped by `Config::MaxBlocksPerInvocation`,
  reads the per-block high-water-mark, probes `key_for_event(block, 0..=hwm)`,
  forwards each present payload via the HTTP client, and deletes the
  consumed offchain entries before checkpointing.

Other notable bits:

- `ConsumerError` Snafu enum keeps the consumer's error stack typed
  end-to-end; the offchain_worker hook formats the error with its
  Display impl.
- Tests use a `TestOffchainExt` + recording-HTTP transport in the mock
  to exercise the full forward path, multi-block cursors, partial
  blocks, lock contention, and resumption from a server checkpoint.
- `ROW_NUMBER_COLUMN_NAME` is the indexer's dedup-key column; lifted to
  `pub` in `commitment-sql` so the consumer can pass it through to
  `create_table` without duplicating the constant.
- `MaxBlocksPerInvocation` (100) and `OcwLockDeadlineMs` (120_000) are
  exposed as `#[pallet::constant]` items so other chains can override
  them and so they show up in metadata for polkadot.js.
…st imports, reuse from_str_unchecked

- `[dev-dependencies]` only needs `parking_lot` (for `RwLock` in the
  offchain-state shared handle the upstream `TestOffchainExt::new` hands
  back). The redundant `polkadot-sdk` dev-dep block was already covered
  by `[dependencies]` in test builds, and none of `pallet-tables` /
  `pallet-indexing` / `pallet-system-tables` / `pallet-zkpay` /
  `pallet-permissions` / `pallet-commitments` /
  `proof-of-sql-commitment-map` are referenced by the mock or tests.
  Visibly speeds up the test-build dep graph.
- Hoist the `use polkadot_sdk::sp_runtime::offchain::{...}` statements
  out of `Pallet::run_consumer` and out of the `ocw_skips_when_lock_is_held`
  test so the module's dependencies are visible at a glance.
- Drop the local `table_id` helper in tests in favor of
  `TableIdentifier::from_str_unchecked` from sxt-core (note the arg
  order: `from_str_unchecked(name, namespace)`).
@rishitesh-snt rishitesh-snt requested review from a team as code owners May 27, 2026 16:35
@github-actions

Copy link
Copy Markdown

1.69.0

Bug Fixes

  • add basic documentation to runtime crate (30c26e7
  • add missing docs for runtime module items (52a2905
  • add missing docs to chain-utils (c8235c6
  • address warnings in on-chain-table (095a856
  • address warnings in pallet-rewards mock module (886bc36
  • allow deprecated CurrencyAdapter usage (cfe0517
  • allow missing docs in private items in test_end_row_limits binary (7700cd6
  • allow missing_docs_in_private_items on event forwarder contract (b2d6f8b
  • allow unused private_key variables in pallet-keystore benchmarks (c218f0d
  • declare anonymous lifetime in commitment-sql proptest helper (63b3fc0
  • declare anonymous lifetimes in canaries parse functions (f81e9de
  • document all items in watcher main module (2fe60db
  • document memory_commitment_map module in commitment-map (32a38e3
  • document missing items in canaries (72c5f33
  • document missing items in event-forwarder (5408075
  • document modules in chain-utils (3eb6545
  • document modules in rpc crate (19cf1af
  • don't hide elided lifetimes in backwards compatibility test case generator (4e6968e
  • don't import frame_benchmarking if runtime-benchmarks is disabled in node (32cfca3
  • expect AttestationInfo::block_number to be dead code in canaries (7753c44
  • expect some dead code in NewFullBase in node (fe06f5e
  • ignore unused error variable in watcher main module (d330fe5
  • ignore unused variable in attestation-tree test (ce8adf3
  • ignore unused variable in pallet-attestation benchmarks (b0ef4a7
  • implement benchmark configurations for runtime outside runtime api implementation (d1a3db8
  • only define migrations with runtime-benchmarks disabled (26e8804
  • privatize deposit_event in pallet-rewards (6c1caaf
  • privatize deposit_event in pallet-smartcontracts (fe43a19
  • privatize deposit_event in pallet-system-tables (8bf7c21
  • privatize deposit_event in pallet-tables (da951a5
  • privatize pallet-keystore deposit_event (e878e37
  • privatize pallet-permissions deposit_event (099a7ba
  • privatize system-contracts deposit_event (305dfc9
  • privatize zkpay deposit_event (9d5993c
  • propagate tui error in update_ui in watcher (fe943eb
  • remove dead code in chain-utils (0070600
  • remove dead code in node (6958ec6
  • remove unused block_number parameter from verify_attestations in watcher (6225426
  • remove unused block_number parameter from verify_signature in watcher (08f3bff
  • remove unused const in pallet-tables test (e7bf9f5
  • remove unused const in runtime test (c7e0add
  • remove unused dependencies from sxt-core (361f8a0
  • remove unused destructure variables in verify_attestation in watcher (dc04d24
  • remove unused import in memory_commitment_map test (4c2300a
  • remove unused import in pallet-attestation benchmarks (5fa662e
  • remove unused import in pallet-commitments migrations (ecf6a05
  • remove unused imports and format imports in chain-utils (5cd269b
  • remove unused imports in attestation-tree (91f5d61
  • remove unused imports in node (1f4c7a8
  • remove unused imports in pallet-smartcontracts (b7fa723
  • remove unused imports in pallet-tables (a08ccfd
  • remove unused imports in runtime (614a1e3
  • remove unused imports in test_end_row_limits (0328143
  • remove unused imports in watcher (340d27b
  • remove unused substrate key path from watcher client (2bd4d02
  • switch hex to being a dev dependency in rpc crate (7b01208
  • warn unused_crate_dependencies in sxt-core (62c85b7

Features

@tlovell-sxt tlovell-sxt left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM thanks for all the iteration on this

@rishitesh-snt rishitesh-snt merged commit ec1d24c into main May 28, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants